package com.cc.blog.web.exception;

import com.cc.blog.common.enums.CodeEnum;
import com.cc.blog.common.exception.BusinessException;
import com.cc.blog.common.utils.Result;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;

import javax.servlet.http.HttpServletRequest;
import java.util.Optional;

/**
 * 异常处理器
 * @author cc
 * @date 2022/8/25 10:47
 */
@RestControllerAdvice
@Slf4j
public class BusinessExceptionHandler {

    /**
     * 处理自定义异常
     */
    @ExceptionHandler(BusinessException.class)
    public Result handleRenException(HttpServletRequest request, BusinessException e){
        log.warn("{} request fail, errorCode: {}, errorMessage: {}", request.getRequestURI(), e.getErrorCode(), e.getErrorMsg());
        return Result.fail(e.getErrorCode(), e.getErrorMsg());
    }


    @ExceptionHandler(Exception.class)
    public Result handleException(HttpServletRequest request,Exception e){
        log.error("{} request error, ", request.getRequestURI(), e);
        return Result.fail(CodeEnum.SYSTEM_ERROR);
    }

    /**
     * 捕获参数校验异常
     * @return
     */
    @ExceptionHandler({ MethodArgumentNotValidException.class })
    public Result handleMethodArgumentNotValidException(HttpServletRequest request, MethodArgumentNotValidException e) {
        // 参数错误异常码
        String errorCode = CodeEnum.PARAM_NOT_VALID.getCode();
        // 获取 BindingResult
        BindingResult bindingResult = e.getBindingResult();
        StringBuilder sb = new StringBuilder();
        // 获取校验不通过的字段，并组合错误信息，格式为： email 邮箱格式不正确, 当前值: '123124qq.com'
        Optional.ofNullable(bindingResult.getFieldErrors())
                .ifPresent(errors ->
                        errors.forEach(error ->
                                sb.append(error.getField())
                                        .append(" ")
                                        .append(error.getDefaultMessage())
                                        .append(", 当前值: '")
                                        .append(error.getRejectedValue())
                                        .append("'; ")
            )
        );
        // 错误信息
        String errorMessage = sb.toString();
        log.warn("{} request error, errorCode: {}, errorMessage: {}", request.getRequestURI(), errorCode, errorMessage);
        return Result.fail(errorCode, errorMessage);
    }

    @ExceptionHandler({ AccessDeniedException.class })
    public void throwAccessDeniedException(AccessDeniedException e) throws AccessDeniedException {
        // 捕获到鉴权失败异常，主动抛出，交给 RestAccessDeniedHandler 去处理
        log.info("============= 捕获到 AccessDeniedException");
        throw e;
    }
}
